package cn.lzm.basic.service.impl;

import cn.lzm.basic.config.BussinessException;
import cn.lzm.basic.constant.BaseConstant;
import cn.lzm.basic.dto.EmailCodeDto;
import cn.lzm.basic.dto.LoginAccountDto;
import cn.lzm.basic.dto.PhoneSmsCodeDto;
import cn.lzm.basic.service.IVerifyCodeService;
import cn.lzm.basic.util.AjaxResult;
import cn.lzm.basic.util.StrUtils;
import cn.lzm.basic.util.VerifyCodeUtils;
import cn.lzm.org.domain.Shop;
import cn.lzm.user.domain.Logininfo;
import cn.lzm.user.domain.User;
import cn.lzm.user.mapper.LogininfoMapper;
import cn.lzm.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private LogininfoMapper logininfoMapper;

    /**
     * 获取图形验证码
     * @param uuidKey
     * @return
     */
    @Override
    public String getImageCode(String uuidKey) {
        // 随机生成数
        String randomCode = StrUtils.getComplexRandomString(4);
        // 存入redis
        redisTemplate.opsForValue().set(uuidKey,randomCode,3, TimeUnit.MINUTES);
        return VerifyCodeUtils.VerifyCode(100,35,randomCode);
    }

    /**
     * 获取验证码
     * @param dto
     */
    @Override
    public void smsCode(PhoneSmsCodeDto dto) {
        // 检验数据是否为空  在controller使用注解
        // 校验手机号是否符合格式 使用正则标的是
        String regex = "^((13[0-9])|(14[05679])|(15([0-3,5-9]))|(16[2567])|(17[01235678])|(18[0-9]|19[135689]))\\d{8}$";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(dto.getPhone());
        boolean isMatch = m.matches();
        if (!isMatch){
            throw new BussinessException("手机格式不正确");
        }
        if ("register".equals(dto.getDistinguish())){
            dto.setType(0);
            // 图形验证码是否正确
            verifyImgageCode(dto);
            // 两次发送短信间隔是否大于60s
            sendSmsCode(String.format(BaseConstant.VerfityCodeCons.REGISTER_SMSCODE_PHONE,dto.getPhone()));
        }else if ("binder".equals(dto.getDistinguish())){
            dto.setType(1);
            sendSmsCode(String.format(BaseConstant.VerfityCodeCons.BINDER_SMSCODE_PHONE,dto.getPhone()));
        }


        // 判断是否重复获取验证码 获取间隔必须大于60秒
        // 【redis中 key：register:smscode:phone  value：验证码:时间戳】
        // 每次将获取到的验证码和时间结合存到redis中，
        // 所以当每次获取验证码是，是不是第一次获取验证码我们都去redis获取验证码和时间结合
        // 将时间和验证码进行分割   使用当前的时间-使用取出来的时间看是否小于60秒  以及 是不是为空  由此来判断两次获取验证码的时间
        // 否则就重新生成验证码 使用随机生成的工具类的方法，再将这个当前时间结合保存到redis中     【然后可以通过短息发送到用户的手机】



    }

    /**
     * 发送验证码
     * @param redisKey
     */
    private void sendSmsCode(String redisKey) {
        String redisSmsCode = (String) redisTemplate.opsForValue().get(redisKey);
        String smsCode = "";
        if (StringUtils.isNotBlank(redisSmsCode)) {
            String[] split = redisSmsCode.split(":");
            smsCode = split[0];
            // 当前时间
            long newTime = System.currentTimeMillis();
            // reids中的时间
            long oldTime = Long.valueOf(split[1]);

            if (newTime - oldTime < 60 * 1000){
                throw new BussinessException("滚！");
            }
        }else {
            // 生成验证码
            smsCode = StrUtils.getRandomString(4);
        }
        log.info("验证码为：{}",smsCode);
        String redisValue = smsCode+":"+ System.currentTimeMillis();
        // 存入到reids
        redisTemplate.opsForValue().set(redisKey,
                redisValue,5,TimeUnit.MINUTES);
        // 发送短信
//        SendSmsUtil.send(dto.getPhone(),"你好：你的验证码为："+smsCode+"，5分钟内有效！");
        // 是否需要重置验证码
    }

    /**
     * 图像验证码校验
     * @param dto
     */
    private void verifyImgageCode(PhoneSmsCodeDto dto) {
        // 验证输入的图片验证码与redis中的图形验证码是否一致
        String imageCode =(String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        log.info(imageCode);
        log.info(dto.getImageCodeValue());
        if (!StringUtils.equalsIgnoreCase(dto.getImageCodeValue(), imageCode)){
            throw new BussinessException("验证码不正确");
        }
        // 当前手机号是否已经注册了
        User user = userMapper.findByPhone(dto.getPhone());
        if (null != user){
            throw new BussinessException("滚去登陆！");
        }
    }

    /**
     * 使用邮箱获取验证码
     * @param dto
     */
    @Override
    public void emailCode(EmailCodeDto dto) {
        // 判断邮箱是否格式是否正确
//        String email=dto.getEmail();
//        String regex="^\\w+([-+.]\\w+)@\\w+([-.]\\w+)\\.\\w+([-.]\\w+)*$";
//        if (!email.matches(regex)){
//            throw new BussinessException("邮箱不正确！");
//        }
        // 验证输入的图片验证码与redis中的图形验证码是否一致
        String imageCode =(String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        log.info(imageCode);
        log.info(dto.getImageCodeValue());
        if (!StringUtils.equalsIgnoreCase(dto.getImageCodeValue(), imageCode)){
            throw new BussinessException("验证码不正确！");
        }
        // 当前手机号是否已经注册了
        User user = userMapper.findByEmail(dto.getEmail());
        if (null != user){
            throw new BussinessException("邮箱已被注册！");
        }

        // 判断是否重复输入验证码
        String redisEmailCode = (String) redisTemplate.opsForValue().get(String.format(BaseConstant.VerfityCodeCons.REGISTER_EMAIL,dto.getEmail()));
        String emailCode = "";
        if (StringUtils.isNotBlank(redisEmailCode)) {
            String[] split = redisEmailCode.split(":");
            emailCode = split[0];
            // 当前时间
            long newTime = System.currentTimeMillis();
            // reids中的时间
            long oldTime = Long.valueOf(split[1]);

            if (newTime - oldTime < 60 * 1000){
                throw new BussinessException("60秒内不能重复获取验证");
            }
        }else {
            // 生成验证码
            emailCode = StrUtils.getRandomString(4);
        }
        log.info("验证码为：{}",emailCode);
        String redisValue = emailCode+":"+ System.currentTimeMillis();
        // 存入到reids
        redisTemplate.opsForValue().set(String.format(BaseConstant.VerfityCodeCons.REGISTER_EMAIL,dto.getEmail()),
                redisValue,5,TimeUnit.MINUTES);
        // 发送邮箱
            // 1.准备发送的相关信息
            SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
            // 1.1.设置发送人
            simpleMailMessage.setFrom("834291384@qq.com");
            // 1.2.设置接收人
            simpleMailMessage.setTo("2561232830@qq.com");
            // 1.3.设置邮件主题
            simpleMailMessage.setSubject("宠物之家店铺邮箱注册验证");
            // 1.4.设置邮件文本内容
            simpleMailMessage.setText("你的验证是,"+ emailCode);
            // 使用邮件核心对象发送邮件
            javaMailSender.send(simpleMailMessage);




//        SendSmsUtil.send(dto.getPhone(),"你好：你的验证码为："+smsCode+"，5分钟内有效！");
        // 是否需要重置验证码
    }

    /**
     * 前台获取手机验证码
     */
    @Override
    public void smsCodeReception(LoginAccountDto dto) {
        // 校验手机号是否符合格式 使用正则标的是
        if (dto.getAccount()==null){
            throw new BussinessException("手机不能为空");
        }

        if (dto.getType()==null){
            throw new BussinessException("手机号不正确");
        }

        String regex = "^((13[0-9])|(14[05679])|(15([0-3,5-9]))|(16[2567])|(17[01235678])|(18[0-9]|19[135689]))\\d{8}$";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(dto.getAccount());
        boolean isMatch = m.matches();
        if (!isMatch){
            throw new BussinessException("手机格式不正确");
        }

        Logininfo logininfo=logininfoMapper.findByPhone(dto.getAccount(),dto.getType());
        if (null == logininfo){
            throw new BussinessException("该手机号没有注册！");
        }

        // 获取验证码和时间的结合体
        String redisSmsCode = (String) redisTemplate.opsForValue().get(String.format(BaseConstant.VerfityCodeCons.Login_SMSCODE_PHONE,dto.getAccount()));
        String smsCode = "";
        if (StringUtils.isNotBlank(redisSmsCode)) {
            String[] split = redisSmsCode.split(":");
            smsCode = split[0];
        }else {
            // 生成验证码
            smsCode = StrUtils.getRandomString(4);
        }
        log.info("验证码为：{}",smsCode);
        String redisValue = smsCode+":"+ System.currentTimeMillis();
        // 存入到reids
        redisTemplate.opsForValue().set(String.format(BaseConstant.VerfityCodeCons.Login_SMSCODE_PHONE,dto.getAccount()),
                redisValue,3,TimeUnit.MINUTES);
    }
}
